home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / C / CRACKLIB.ZIP / CRACKLIB.TAR / cracklib25_small / cracklib / rules.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-09  |  15.1 KB  |  831 lines

  1. /*
  2.  * This program is copyright Alec Muffett 1993. The author disclaims all 
  3.  * responsibility or liability with respect to it's usage or its effect 
  4.  * upon hardware or computer systems, and maintains copyright as set out 
  5.  * in the "LICENCE" document which accompanies distributions of Crack v4.0 
  6.  * and upwards.
  7.  */
  8.  
  9. static char vers_id[] = "rules.c : v5.0p3 Alec Muffett 20 May 1993";
  10.  
  11. #ifndef IN_CRACKLIB
  12.  
  13. #include "crack.h"
  14.  
  15. #else
  16.  
  17. #include "packer.h"
  18.  
  19. static void
  20. Debug(val, a, b, c, d, e, f, g)
  21.     int val;
  22.     char *a, *b, *c, *d, *e, *f, *g;
  23. {
  24.     fprintf(stderr, a, b, c, d, e, f);
  25. }
  26.  
  27. #endif
  28.  
  29. #define RULE_NOOP    ':'
  30. #define RULE_PREPEND    '^'
  31. #define RULE_APPEND    '$'
  32. #define RULE_REVERSE    'r'
  33. #define RULE_UPPERCASE    'u'
  34. #define RULE_LOWERCASE    'l'
  35. #define RULE_PLURALISE    'p'
  36. #define RULE_CAPITALISE    'c'
  37. #define RULE_DUPLICATE    'd'
  38. #define RULE_REFLECT    'f'
  39. #define RULE_SUBSTITUTE    's'
  40. #define RULE_MATCH    '/'
  41. #define RULE_NOT    '!'
  42. #define RULE_LT        '<'
  43. #define RULE_GT        '>'
  44. #define RULE_EXTRACT    'x'
  45. #define RULE_OVERSTRIKE    'o'
  46. #define RULE_INSERT    'i'
  47. #define RULE_EQUALS    '='
  48. #define RULE_PURGE    '@'
  49. #define RULE_CLASS    '?'    /* class rule? socialist ethic in cracker? */
  50.  
  51. #define RULE_DFIRST    '['
  52. #define RULE_DLAST    ']'
  53. #define RULE_MFIRST    '('
  54. #define RULE_MLAST    ')'
  55.  
  56. int
  57. Suffix(myword, suffix)
  58.     char *myword;
  59.     char *suffix;
  60. {
  61.     register int i;
  62.     register int j;
  63.     i = strlen(myword);
  64.     j = strlen(suffix);
  65.  
  66.     if (i > j)
  67.     {
  68.     return (STRCMP((myword + i - j), suffix));
  69.     } else
  70.     {
  71.     return (-1);
  72.     }
  73. }
  74.  
  75. char *
  76. Reverse(str)            /* return a pointer to a reversal */
  77.     register char *str;
  78. {
  79.     register int i;
  80.     register int j;
  81.     static char area[STRINGSIZE];
  82.     j = i = strlen(str);
  83.     while (*str)
  84.     {
  85.     area[--i] = *str++;
  86.     }
  87.     area[j] = '\0';
  88.     return (area);
  89. }
  90.  
  91. char *
  92. Uppercase(str)            /* return a pointer to an uppercase */
  93.     register char *str;
  94. {
  95.     register char *ptr;
  96.     static char area[STRINGSIZE];
  97.     ptr = area;
  98.     while (*str)
  99.     {
  100.     *(ptr++) = CRACK_TOUPPER(*str);
  101.     str++;
  102.     }
  103.     *ptr = '\0';
  104.  
  105.     return (area);
  106. }
  107.  
  108. char *
  109. Lowercase(str)            /* return a pointer to an lowercase */
  110.     register char *str;
  111. {
  112.     register char *ptr;
  113.     static char area[STRINGSIZE];
  114.     ptr = area;
  115.     while (*str)
  116.     {
  117.     *(ptr++) = CRACK_TOLOWER(*str);
  118.     str++;
  119.     }
  120.     *ptr = '\0';
  121.  
  122.     return (area);
  123. }
  124.  
  125. char *
  126. Capitalise(str)            /* return a pointer to an capitalised */
  127.     register char *str;
  128. {
  129.     register char *ptr;
  130.     static char area[STRINGSIZE];
  131.     ptr = area;
  132.  
  133.     while (*str)
  134.     {
  135.     *(ptr++) = CRACK_TOLOWER(*str);
  136.     str++;
  137.     }
  138.  
  139.     *ptr = '\0';
  140.     area[0] = CRACK_TOUPPER(area[0]);
  141.     return (area);
  142. }
  143.  
  144. char *
  145. Pluralise(string)        /* returns a pointer to a plural */
  146.     register char *string;
  147. {
  148.     register int length;
  149.     static char area[STRINGSIZE];
  150.     length = strlen(string);
  151.     strcpy(area, string);
  152.  
  153.     if (!Suffix(string, "ch") ||
  154.     !Suffix(string, "ex") ||
  155.     !Suffix(string, "ix") ||
  156.     !Suffix(string, "sh") ||
  157.     !Suffix(string, "ss"))
  158.     {
  159.     /* bench -> benches */
  160.     strcat(area, "es");
  161.     } else if (length > 2 && string[length - 1] == 'y')
  162.     {
  163.     if (strchr("aeiou", string[length - 2]))
  164.     {
  165.         /* alloy -> alloys */
  166.         strcat(area, "s");
  167.     } else
  168.     {
  169.         /* gully -> gullies */
  170.         strcpy(area + length - 1, "ies");
  171.     }
  172.     } else if (string[length - 1] == 's')
  173.     {
  174.     /* bias -> biases */
  175.     strcat(area, "es");
  176.     } else
  177.     {
  178.     /* catchall */
  179.     strcat(area, "s");
  180.     }
  181.  
  182.     return (area);
  183. }
  184.  
  185. char *
  186. Substitute(string, old, new)    /* returns pointer to a swapped about copy */
  187.     register char *string;
  188.     register char old;
  189.     register char new;
  190. {
  191.     register char *ptr;
  192.     static char area[STRINGSIZE];
  193.     ptr = area;
  194.     while (*string)
  195.     {
  196.     *(ptr++) = (*string == old ? new : *string);
  197.     string++;
  198.     }
  199.     *ptr = '\0';
  200.     return (area);
  201. }
  202.  
  203. char *
  204. Purge(string, target)        /* returns pointer to a purged copy */
  205.     register char *string;
  206.     register char target;
  207. {
  208.     register char *ptr;
  209.     static char area[STRINGSIZE];
  210.     ptr = area;
  211.     while (*string)
  212.     {
  213.     if (*string != target)
  214.     {
  215.         *(ptr++) = *string;
  216.     }
  217.     string++;
  218.     }
  219.     *ptr = '\0';
  220.     return (area);
  221. }
  222. /* -------- CHARACTER CLASSES START HERE -------- */
  223.  
  224. /*
  225.  * this function takes two inputs, a class identifier and a character, and
  226.  * returns non-null if the given character is a member of the class, based
  227.  * upon restrictions set out below
  228.  */
  229.  
  230. int
  231. MatchClass(class, input)
  232.     register char class;
  233.     register char input;
  234. {
  235.     register char c;
  236.     register int retval;
  237.     retval = 0;
  238.  
  239.     switch (class)
  240.     {
  241.     /* ESCAPE */
  242.  
  243.     case '?':            /* ?? -> ? */
  244.     if (input == '?')
  245.     {
  246.         retval = 1;
  247.     }
  248.     break;
  249.  
  250.     /* ILLOGICAL GROUPINGS (ie: not in ctype.h) */
  251.  
  252.     case 'V':
  253.     case 'v':            /* vowels */
  254.     c = CRACK_TOLOWER(input);
  255.     if (strchr("aeiou", c))
  256.     {
  257.         retval = 1;
  258.     }
  259.     break;
  260.  
  261.     case 'C':
  262.     case 'c':            /* consonants */
  263.     c = CRACK_TOLOWER(input);
  264.     if (strchr("bcdfghjklmnpqrstvwxyz", c))
  265.     {
  266.         retval = 1;
  267.     }
  268.     break;
  269.  
  270.     case 'W':
  271.     case 'w':            /* whitespace */
  272.     if (strchr("\t ", input))
  273.     {
  274.         retval = 1;
  275.     }
  276.     break;
  277.  
  278.     case 'P':
  279.     case 'p':            /* punctuation */
  280.     if (strchr(".`,:;'!?\"", input))
  281.     {
  282.         retval = 1;
  283.     }
  284.     break;
  285.  
  286.     case 'S':
  287.     case 's':            /* symbols */
  288.     if (strchr("$%%^&*()-_+=|\\[]{}#@/~", input))
  289.     {
  290.         retval = 1;
  291.     }
  292.     break;
  293.  
  294.     /* LOGICAL GROUPINGS */
  295.  
  296.     case 'L':
  297.     case 'l':            /* lowercase */
  298.     if (islower(input))
  299.     {
  300.         retval = 1;
  301.     }
  302.     break;
  303.  
  304.     case 'U':
  305.     case 'u':            /* uppercase */
  306.     if (isupper(input))
  307.     {
  308.         retval = 1;
  309.     }
  310.     break;
  311.  
  312.     case 'A':
  313.     case 'a':            /* alphabetic */
  314.     if (isalpha(input))
  315.     {
  316.         retval = 1;
  317.     }
  318.     break;
  319.  
  320.     case 'X':
  321.     case 'x':            /* alphanumeric */
  322.     if (isalnum(input))
  323.     {
  324.         retval = 1;
  325.     }
  326.     break;
  327.  
  328.     case 'D':
  329.     case 'd':            /* digits */
  330.     if (isdigit(input))
  331.     {
  332.         retval = 1;
  333.     }
  334.     break;
  335.  
  336.     default:
  337.     Debug(1, "MatchClass: unknown class %c\n", class);
  338.     return (0);
  339.     break;
  340.     }
  341.  
  342.     if (isupper(class))
  343.     {
  344.     return (!retval);
  345.     }
  346.     return (retval);
  347. }
  348.  
  349. char *
  350. PolyStrchr(string, class)
  351.     register char *string;
  352.     register char class;
  353. {
  354.     while (*string)
  355.     {
  356.     if (MatchClass(class, *string))
  357.     {
  358.         return (string);
  359.     }
  360.     string++;
  361.     }
  362.     return ((char *) 0);
  363. }
  364.  
  365. char *
  366. PolySubst(string, class, new)    /* returns pointer to a swapped about copy */
  367.     register char *string;
  368.     register char class;
  369.     register char new;
  370. {
  371.     register char *ptr;
  372.     static char area[STRINGSIZE];
  373.     ptr = area;
  374.     while (*string)
  375.     {
  376.     *(ptr++) = (MatchClass(class, *string) ? new : *string);
  377.     string++;
  378.     }
  379.     *ptr = '\0';
  380.     return (area);
  381. }
  382.  
  383. char *
  384. PolyPurge(string, class)    /* returns pointer to a purged copy */
  385.     register char *string;
  386.     register char class;
  387. {
  388.     register char *ptr;
  389.     static char area[STRINGSIZE];
  390.     ptr = area;
  391.     while (*string)
  392.     {
  393.     if (!MatchClass(class, *string))
  394.     {
  395.         *(ptr++) = *string;
  396.     }
  397.     string++;
  398.     }
  399.     *ptr = '\0';
  400.     return (area);
  401. }
  402. /* -------- BACK TO NORMALITY -------- */
  403.  
  404. int
  405. Char2Int(character)
  406.     char character;
  407. {
  408.     if (isdigit(character))
  409.     {
  410.     return (character - '0');
  411.     } else if (islower(character))
  412.     {
  413.     return (character - 'a' + 10);
  414.     } else if (isupper(character))
  415.     {
  416.     return (character - 'A' + 10);
  417.     }
  418.     return (-1);
  419. }
  420.  
  421. char *
  422. Mangle(input, control)        /* returns a pointer to a controlled Mangle */
  423.     char *input;
  424.     char *control;
  425. {
  426.     int limit;
  427.     register char *ptr;
  428.     static char area[STRINGSIZE];
  429.     char area2[STRINGSIZE];
  430.     area[0] = '\0';
  431.     strcpy(area, input);
  432.  
  433.     for (ptr = control; *ptr; ptr++)
  434.     {
  435.     switch (*ptr)
  436.     {
  437.     case RULE_NOOP:
  438.         break;
  439.     case RULE_REVERSE:
  440.         strcpy(area, Reverse(area));
  441.         break;
  442.     case RULE_UPPERCASE:
  443.         strcpy(area, Uppercase(area));
  444.         break;
  445.     case RULE_LOWERCASE:
  446.         strcpy(area, Lowercase(area));
  447.         break;
  448.     case RULE_CAPITALISE:
  449.         strcpy(area, Capitalise(area));
  450.         break;
  451.     case RULE_PLURALISE:
  452.         strcpy(area, Pluralise(area));
  453.         break;
  454.     case RULE_REFLECT:
  455.         strcat(area, Reverse(area));
  456.         break;
  457.     case RULE_DUPLICATE:
  458.         strcpy(area2, area);
  459.         strcat(area, area2);
  460.         break;
  461.     case RULE_GT:
  462.         if (!ptr[1])
  463.         {
  464.         Debug(1, "Mangle: '>' missing argument in '%s'\n", control);
  465.         return ((char *) 0);
  466.         } else
  467.         {
  468.         limit = Char2Int(*(++ptr));
  469.         if (limit < 0)
  470.         {
  471.             Debug(1, "Mangle: '>' weird argument in '%s'\n", control);
  472.             return ((char *) 0);
  473.         }
  474.         if (strlen(area) <= limit)
  475.         {
  476.             return ((char *) 0);
  477.         }
  478.         }
  479.         break;
  480.     case RULE_LT:
  481.         if (!ptr[1])
  482.         {
  483.         Debug(1, "Mangle: '<' missing argument in '%s'\n", control);
  484.         return ((char *) 0);
  485.         } else
  486.         {
  487.         limit = Char2Int(*(++ptr));
  488.         if (limit < 0)
  489.         {
  490.             Debug(1, "Mangle: '<' weird argument in '%s'\n", control);
  491.             return ((char *) 0);
  492.         }
  493.         if (strlen(area) >= limit)
  494.         {
  495.             return ((char *) 0);
  496.         }
  497.         }
  498.         break;
  499.     case RULE_PREPEND:
  500.         if (!ptr[1])
  501.         {
  502.         Debug(1, "Mangle: prepend missing argument in '%s'\n", control);
  503.         return ((char *) 0);
  504.         } else
  505.         {
  506.         area2[0] = *(++ptr);
  507.         strcpy(area2 + 1, area);
  508.         strcpy(area, area2);
  509.         }
  510.         break;
  511.     case RULE_APPEND:
  512.         if (!ptr[1])
  513.         {
  514.         Debug(1, "Mangle: append missing argument in '%s'\n", control);
  515.         return ((char *) 0);
  516.         } else
  517.         {
  518.         register char *string;
  519.         string = area;
  520.         while (*(string++));
  521.         string[-1] = *(++ptr);
  522.         *string = '\0';
  523.         }
  524.         break;
  525.     case RULE_EXTRACT:
  526.         if (!ptr[1] || !ptr[2])
  527.         {
  528.         Debug(1, "Mangle: extract missing argument in '%s'\n", control);
  529.         return ((char *) 0);
  530.         } else
  531.         {
  532.         register int i;
  533.         int start;
  534.         int length;
  535.         start = Char2Int(*(++ptr));
  536.         length = Char2Int(*(++ptr));
  537.         if (start < 0 || length < 0)
  538.         {
  539.             Debug(1, "Mangle: extract: weird argument in '%s'\n", control);
  540.             return ((char *) 0);
  541.         }
  542.         strcpy(area2, area);
  543.         for (i = 0; length-- && area2[start + i]; i++)
  544.         {
  545.             area[i] = area2[start + i];
  546.         }
  547.         /* cant use strncpy() - no trailing NUL */
  548.         area[i] = '\0';
  549.         }
  550.         break;
  551.     case RULE_OVERSTRIKE:
  552.         if (!ptr[1] || !ptr[2])
  553.         {
  554.         Debug(1, "Mangle: overstrike missing argument in '%s'\n", control);
  555.         return ((char *) 0);
  556.         } else
  557.         {
  558.         register int i;
  559.         i = Char2Int(*(++ptr));
  560.         if (i < 0)
  561.         {
  562.             Debug(1, "Mangle: overstrike weird argument in '%s'\n",
  563.               control);
  564.             return ((char *) 0);
  565.         } else
  566.         {
  567.             ++ptr;
  568.             if (area[i])
  569.             {
  570.             area[i] = *ptr;
  571.             }
  572.         }
  573.         }
  574.         break;
  575.     case RULE_INSERT:
  576.         if (!ptr[1] || !ptr[2])
  577.         {
  578.         Debug(1, "Mangle: insert missing argument in '%s'\n", control);
  579.         return ((char *) 0);
  580.         } else
  581.         {
  582.         register int i;
  583.         register char *p1;
  584.         register char *p2;
  585.         i = Char2Int(*(++ptr));
  586.         if (i < 0)
  587.         {
  588.             Debug(1, "Mangle: insert weird argument in '%s'\n",
  589.               control);
  590.             return ((char *) 0);
  591.         }
  592.         p1 = area;
  593.         p2 = area2;
  594.         while (i && *p1)
  595.         {
  596.             i--;
  597.             *(p2++) = *(p1++);
  598.         }
  599.         *(p2++) = *(++ptr);
  600.         strcpy(p2, p1);
  601.         strcpy(area, area2);
  602.         }
  603.         break;
  604.         /* THE FOLLOWING RULES REQUIRE CLASS MATCHING */
  605.  
  606.     case RULE_PURGE:    /* @x or @?c */
  607.         if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
  608.         {
  609.         Debug(1, "Mangle: delete missing arguments in '%s'\n", control);
  610.         return ((char *) 0);
  611.         } else if (ptr[1] != RULE_CLASS)
  612.         {
  613.         strcpy(area, Purge(area, *(++ptr)));
  614.         } else
  615.         {
  616.         strcpy(area, PolyPurge(area, ptr[2]));
  617.         ptr += 2;
  618.         }
  619.         break;
  620.     case RULE_SUBSTITUTE:    /* sxy || s?cy */
  621.         if (!ptr[1] || !ptr[2] || (ptr[1] == RULE_CLASS && !ptr[3]))
  622.         {
  623.         Debug(1, "Mangle: subst missing argument in '%s'\n", control);
  624.         return ((char *) 0);
  625.         } else if (ptr[1] != RULE_CLASS)
  626.         {
  627.         strcpy(area, Substitute(area, ptr[1], ptr[2]));
  628.         ptr += 2;
  629.         } else
  630.         {
  631.         strcpy(area, PolySubst(area, ptr[2], ptr[3]));
  632.         ptr += 3;
  633.         }
  634.         break;
  635.     case RULE_MATCH:    /* /x || /?c */
  636.         if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
  637.         {
  638.         Debug(1, "Mangle: '/' missing argument in '%s'\n", control);
  639.         return ((char *) 0);
  640.         } else if (ptr[1] != RULE_CLASS)
  641.         {
  642.         if (!strchr(area, *(++ptr)))
  643.         {
  644.             return ((char *) 0);
  645.         }
  646.         } else
  647.         {
  648.         if (!PolyStrchr(area, ptr[2]))
  649.         {
  650.             return ((char *) 0);
  651.         }
  652.         ptr += 2;
  653.         }
  654.         break;
  655.     case RULE_NOT:        /* !x || !?c */
  656.         if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
  657.         {
  658.         Debug(1, "Mangle: '!' missing argument in '%s'\n", control);
  659.         return ((char *) 0);
  660.         } else if (ptr[1] != RULE_CLASS)
  661.         {
  662.         if (strchr(area, *(++ptr)))
  663.         {
  664.             return ((char *) 0);
  665.         }
  666.         } else
  667.         {
  668.         if (PolyStrchr(area, ptr[2]))
  669.         {
  670.             return ((char *) 0);
  671.         }
  672.         ptr += 2;
  673.         }
  674.         break;
  675.         /*
  676.          * alternative use for a boomerang, number 1: a standard throwing
  677.          * boomerang is an ideal thing to use to tuck the sheets under
  678.          * the mattress when making your bed.  The streamlined shape of
  679.          * the boomerang allows it to slip easily 'twixt mattress and
  680.          * bedframe, and it's curve makes it very easy to hook sheets
  681.          * into the gap.
  682.          */
  683.  
  684.     case RULE_EQUALS:    /* =nx || =n?c */
  685.         if (!ptr[1] || !ptr[2] || (ptr[2] == RULE_CLASS && !ptr[3]))
  686.         {
  687.         Debug(1, "Mangle: '=' missing argument in '%s'\n", control);
  688.         return ((char *) 0);
  689.         } else
  690.         {
  691.         register int i;
  692.         if ((i = Char2Int(ptr[1])) < 0)
  693.         {
  694.             Debug(1, "Mangle: '=' weird argument in '%s'\n", control);
  695.             return ((char *) 0);
  696.         }
  697.         if (ptr[2] != RULE_CLASS)
  698.         {
  699.             ptr += 2;
  700.             if (area[i] != *ptr)
  701.             {
  702.             return ((char *) 0);
  703.             }
  704.         } else
  705.         {
  706.             ptr += 3;
  707.             if (!MatchClass(*ptr, area[i]))
  708.             {
  709.             return ((char *) 0);
  710.             }
  711.         }
  712.         }
  713.         break;
  714.  
  715.     case RULE_DFIRST:
  716.         if (area[0])
  717.         {
  718.         register int i;
  719.         for (i = 1; area[i]; i++)
  720.         {
  721.             area[i - 1] = area[i];
  722.         }
  723.         area[i - 1] = '\0';
  724.         }
  725.         break;
  726.  
  727.     case RULE_DLAST:
  728.         if (area[0])
  729.         {
  730.         register int i;
  731.         for (i = 1; area[i]; i++);
  732.         area[i - 1] = '\0';
  733.         }
  734.         break;
  735.  
  736.     case RULE_MFIRST:
  737.         if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
  738.         {
  739.         Debug(1, "Mangle: '(' missing argument in '%s'\n", control);
  740.         return ((char *) 0);
  741.         } else
  742.         {
  743.         if (ptr[1] != RULE_CLASS)
  744.         {
  745.             ptr++;
  746.             if (area[0] != *ptr)
  747.             {
  748.             return ((char *) 0);
  749.             }
  750.         } else
  751.         {
  752.             ptr += 2;
  753.             if (!MatchClass(*ptr, area[0]))
  754.             {
  755.             return ((char *) 0);
  756.             }
  757.         }
  758.         }
  759.     case RULE_MLAST:
  760.         if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
  761.         {
  762.         Debug(1, "Mangle: ')' missing argument in '%s'\n", control);
  763.         return ((char *) 0);
  764.         } else
  765.         {
  766.         register int i;
  767.  
  768.         for (i = 0; area[i]; i++);
  769.  
  770.         if (i > 0)
  771.         {
  772.             i--;
  773.         } else
  774.         {
  775.             return ((char *) 0);
  776.         }
  777.  
  778.         if (ptr[1] != RULE_CLASS)
  779.         {
  780.             ptr++;
  781.             if (area[i] != *ptr)
  782.             {
  783.             return ((char *) 0);
  784.             }
  785.         } else
  786.         {
  787.             ptr += 2;
  788.             if (!MatchClass(*ptr, area[i]))
  789.             {
  790.             return ((char *) 0);
  791.             }
  792.         }
  793.         }
  794.  
  795.     default:
  796.         Debug(1, "Mangle: unknown command %c in %s\n", *ptr, control);
  797.         return ((char *) 0);
  798.         break;
  799.     }
  800.     }
  801.     if (!area[0])        /* have we deweted de poor widdle fing away? */
  802.     {
  803.     return ((char *) 0);
  804.     }
  805.     return (area);
  806. }
  807.  
  808. int
  809. PMatch(control, string)
  810. register char *control;
  811. register char *string;
  812. {
  813.     while (*string && *control)
  814.     {
  815.         if (!MatchClass(*control, *string))
  816.         {
  817.             return(0);
  818.         }
  819.  
  820.         string++;
  821.         control++;
  822.     }
  823.  
  824.     if (*string || *control)
  825.     {
  826.         return(0);
  827.     }
  828.  
  829.     return(1);
  830. }
  831.